package com.example.demo.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.BeansException;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据源的相关配置
 */
@SpringBootConfiguration
public class DataSourceConfig implements ApplicationContextAware {

    private ApplicationContext applicationContext;



    /**
     * $.namespace = function() {
     *     var a=arguments, o=null, i, j, d;
     *     for (i=0; i<a.length; i=i+1) {
     *         d=a[i].split(".");
     *         o=window;
     *         for (j=0; j<d.length; j=j+1) {
     *             o[d[j]]=o[d[j]] || {};
     *             o=o[d[j]];
     *         }
     *     }
     *     return o;
     * };
     * DruidDataSource 属性的具体含义配置 https://blog.csdn.net/q343509740/article/details/80577839
     */
    @ConfigurationProperties(prefix = "spring.datasource.druid")
    @Bean(initMethod = "init", destroyMethod = "close")
    public DruidDataSource dataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        List<Filter>    statFilters     = Collections.singletonList(statFilter());
        druidDataSource.setProxyFilters(statFilters);
        return druidDataSource;
    }

    //注册 servlet
    @Bean
    public ServletRegistrationBean<StatViewServlet> servletRegistrationBean() {
        ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        registrationBean.setLoadOnStartup(1);
        Map<String, String> initParams = new HashMap<>();
        //网页登陆用户和密码(不配置，可免登陆)
        initParams.put("loginUsername", "admin"); //参数名查看 com.alibaba.druid.support.http.ResourceServlet
        initParams.put("loginPassword", "admin");
        //IP白名单
        initParams.put("allow", ""); //允许访问
        //IP黑名单，若有一个ip都在两个里面，优先deny
        //initParams.put("deny","192.168.2.126");//拒绝访问
        registrationBean.setInitParameters(initParams);
        return registrationBean;
    }

    @Bean
    public StatFilter statFilter() {
        StatFilter statFilter = new StatFilter();
        //多长时间定义为慢sql，单位毫秒
        statFilter.setSlowSqlMillis(5000);
        //是否打印出慢日志
        statFilter.setLogSlowSql(true);
        //是否将日志合并起来
        statFilter.setMergeSql(true);
        return statFilter;
    }


    //注册filter
    @Bean
    public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() {
        FilterRegistrationBean<WebStatFilter> bean       = new FilterRegistrationBean<>(new WebStatFilter());
        Map<String, String>                   initParams = new HashMap<>();
        initParams.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,*.jsp,/druid/*"); // 不拦截的请求 参数名查看 com.alibaba.druid.support.http.WebStatFilter
        bean.setInitParameters(initParams);
        bean.setUrlPatterns(Collections.singletonList("/*")); //拦截后内部的处理看WebStatFilter*//*
        return bean;
    }

    //Spring 方法监控  ================================================================================
    @Bean
    public DruidStatInterceptor druidStatInterceptor() {
        return new DruidStatInterceptor();
    }

    //切入点
    @Bean
    public JdkRegexpMethodPointcut jdkRegexpMethodPointcut() {
        JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
        jdkRegexpMethodPointcut.setPatterns(Constant.BASE_PACKAGE + ".service");
        return jdkRegexpMethodPointcut;
    }

    @Bean
    public Advisor druidAdvisor(DruidStatInterceptor druidStatInterceptor, JdkRegexpMethodPointcut jdkRegexpMethodPointcut) {
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(jdkRegexpMethodPointcut);
        defaultPointcutAdvisor.setAdvice(druidStatInterceptor);
        return defaultPointcutAdvisor;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

